﻿// DigitalDesign
// Project: InformationBoard
// Developer: Baevskih Aleksandr
// Created: 13.11.2011
// Last change: 21.11.2011

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.IO;
using System.Configuration;

namespace Server
{
    // ПРИМЕЧАНИЕ. Команду "Переименовать" в меню "Рефакторинг" можно использовать для одновременного изменения имени класса "VideoServices" в коде и файле конфигурации.
    public class VideoService : IVideoService
    {
        DataModelContainer DataBase = new DataModelContainer();
        Server.alex.ServiceSettings Settings = new Server.alex.ServiceSettings();
      
        #region Video
        //Задаем размер видео буффера
        public void SetVideoBufferSize(int Value)
        {
            Settings.PropertyValues["VideoBufferSize"].PropertyValue = Value;
            Settings.Save();
        }

        //Получаем размер видео буффера
        public int GetVideoBufferSize()
        {
            return Settings.VideoBufferSize;
        }

        //Достаем путь к файлам с видео из опций
        public string GetVideoDirectory()
        {
            return Settings.VideoDirectory;
        }

        public void SetVideoDirectory(string Directory)
        {
            if (!System.IO.Directory.Exists(Directory))
                throw new Exception(String.Format("Video service error: Bad directory \"{0}\".", Directory));
            
            Settings.PropertyValues["VideoDirectory"].PropertyValue = Directory;
            Settings.Save();
        }

        //Добавление новой видеозаписи в базу
        public void AddVideo(string FileName, string Description)
        {
            if (GetVideoDirectory() == null)
                throw new Exception(String.Format("Video service error: Bad directory \"{0}\".", GetVideoDirectory()));

            var _path = String.Format("{0}{1}", GetVideoDirectory(), FileName); //Собираем полный путь к файлу
            
            if (!System.IO.File.Exists(_path)) 
                throw new Exception("Video service error: File does not exist.");

            if ((from _videos in DataBase.Videos 
                 where _videos.FileName == FileName 
                 select _videos).Count() != 0)
                throw new Exception("Video service error: Database already contains this video.");

            Video video = new Video();
            video.FileName = FileName;
            video.Description = Description;

            DataBase.AddObject("Videos", video);
            DataBase.SaveChanges();
        }

        //Отправка видео на клиент
        public bool SendVideo(int VideoID, int ClientID, out byte[] Buffer, out int BufferSize)
        {
            var _path = "";
            var _settingsName = String.Format("{0}{1}Offset", ClientID, VideoID);
            BufferSize = (int)Settings.VideoBufferSize;

            if ((from _clients in DataBase.ClientDevices
                 where _clients.Id == ClientID
                 select _clients).Count() == 0)
                throw new Exception(String.Format("Video service error: Wrong client ID - {0}", ClientID));
            
            try
            {
                _path = String.Format("{0}{1}", GetVideoDirectory(), (from _videos in DataBase.Videos
                                                                      where _videos.Id == VideoID
                                                                      select _videos).First().FileName);
            }
            catch
            {
                throw new Exception("Video service error: Database does not contain this video.");
            }

            if (!File.Exists(_path))
                throw new Exception(String.Format("Video service error: This video file does not exist - {0}.", _path));

            FileStream _fileStream = new FileStream(_path, FileMode.Open, FileAccess.Read);

            if (Settings.Properties[_settingsName] == null)
            {
                SettingsProperty settingsBuffer = new SettingsProperty(_settingsName);
                settingsBuffer.PropertyType = typeof(long);
                Settings.Properties.Add(settingsBuffer);
                Settings.PropertyValues.Add(new SettingsPropertyValue(settingsBuffer));
                Settings.Save();
            }

            var _currentOffset = (long)Settings.PropertyValues[_settingsName].PropertyValue;
            var _bufferSize = (int)((_fileStream.Length >= (long)BufferSize + _currentOffset) ? BufferSize : _fileStream.Length - _currentOffset);

            Buffer = new byte[_bufferSize];
            BufferSize = _bufferSize;

            _fileStream.Position = _currentOffset;
            _fileStream.Read(Buffer, 0, _bufferSize);
            Console.WriteLine("Current offset: {0} BufferSize: {1} \nFileSize: {2} Position: {3}", _currentOffset, _bufferSize, _fileStream.Length, _fileStream.Position);

            Settings.PropertyValues[_settingsName].PropertyValue = _currentOffset + _bufferSize;

            if (_fileStream.Length == _currentOffset + _bufferSize)
            {
                Settings.Properties.Remove(_settingsName);
                Settings.Save();
                _fileStream.Close();
                return true;
            }

            _fileStream.Close();
            Settings.Save();

            return false;
        }

        //Отправка списка видео администратору
        public VideoWarp GetListOfVideo()
        {
            VideoWarp vWarp = new VideoWarp();
            //Если обертка не пустая, возвращаем её
            if (vWarp.CreateWarp())
                return vWarp;

            throw new Exception("Video service error: Data base does not contain any video-files.");
        }

        //Отправка списка видео конкретного клиента администратору
        public VideoWarp GetListOfVideoOnClient(int ClientID)
        {
            VideoWarp vWarp = new VideoWarp();
            if (vWarp.CreateWarp(ClientID))
                return vWarp;

            throw new Exception(String.Format("Video service error: Data base does not contain any video-files for current client. ID - {0}", ClientID));
        }

        #endregion
        #region Playlist
        //Добавление плейлиста в базу
        public void AddPlaylist(DateTime StartTime, DateTime EndTime, int VideoID, int ClientID, int DayOfWeekID)
        {
            if (StartTime > EndTime) 
                throw new Exception("Video service error: Start time must be less than end time.");

            var _code = "";
            var Day = "";

            //Проверяем существование ключей
            try
            {
                _code = "DayOfWeek ID is incorrect.";
                Day = (from _days in DataBase.DaysOfWeeks 
                       where _days.Id == DayOfWeekID 
                       select _days).First().Name;

                _code = "Video ID is incorrect.";

                (from _video in DataBase.Videos 
                 where _video.Id == VideoID 
                 select _video).First();

                _code = "Client ID is incorrect.";

                (from _client in DataBase.ClientDevices 
                 where _client.Id == ClientID 
                 select _client).First();
            }
            catch
            { 
                throw new Exception(String.Format("Video service error: {0}", _code));
            }

            Playlist playlist = new Playlist();
            playlist.ClientDevice_Id = ClientID;
            playlist.DaysOfWeek_Id = DayOfWeekID;
            playlist.Video_Id = VideoID;
            playlist.TimeOfBegin = StartTime;
            playlist.TimeOfEnd = EndTime;

            DataBase.AddObject("Playlists", playlist);
            DataVersionManager.Instance.IncVideoVersion(ClientID);
            DataBase.SaveChanges();
        }

        //Удаление плейлиста из базы
        public void DeletePlaylist(int PlaylistID)
        {
            Playlist playlist = new Playlist();
            
            //Проверяем, существует ли плейлист
            try
            { 
                playlist = (from _playlists in DataBase.Playlists
                            where _playlists.Id == PlaylistID 
                            select _playlists).First();
            }
            catch
            { 
                throw new Exception(String.Format("Video service error: Current playlist does not exist. ID - {0}.", PlaylistID)); 
            }

            var Day = (from _days in DataBase.DaysOfWeeks
                       where _days.Id == playlist.DaysOfWeek_Id
                       select _days).First().Name;

            DataBase.DeleteObject(playlist);
            DataVersionManager.Instance.IncVideoVersion(playlist.ClientDevice_Id);
            DataBase.SaveChanges();
            SendOrGetPlaylist(playlist.ClientDevice_Id, false, Day);
        }

        #region Отправка клиенту/администратору плейлиста(аргумент DayOfWeek принимает значение null в случае, когда плейлист нужен на неделю)

        public List<PlaylistWarp> GetPlaylist(int ClientID, string DayOfWeek)
        {
            return SendOrGetPlaylist(ClientID, true, DayOfWeek);
        }

        public List<PlaylistWarp> SendPlaylist(int ClientID, string DayOfWeek)
        {
            return SendOrGetPlaylist(ClientID, false, DayOfWeek);
        }

        private List<PlaylistWarp> SendOrGetPlaylist(int ClientID, bool ToAdmin, string DayOfWeek)
        {
            if ((from Client in DataBase.ClientDevices
                 where ClientID == Client.Id
                 select Client).Count() == 0)
                throw new Exception(String.Format("Video service error: Wrong client ID - {0}.", ClientID));

            var _sendAll = DayOfWeek == null;
            var _code = 0;

            List<PlaylistWarp> listOfWarp = new List<PlaylistWarp>();

            //Отправляем на неделю
            if (_sendAll)
            {
                foreach (DaysOfWeek tempDay in (from _days in DataBase.DaysOfWeeks select _days))
                {
                    listOfWarp.Add(new PlaylistWarp(ClientID));
                    _code = listOfWarp.Last().CreateWarp(tempDay.Name, ToAdmin);
                    listOfWarp.Last().Version = DataVersionManager.Instance.GetDataVersionEx(ClientID);

                    //Удаляем "конфету", если она пустая
                    if (_code != 0)
                        listOfWarp.RemoveAt(listOfWarp.Count - 1);
                }
            }
            //Отправляем на день
            else
            {
                listOfWarp.Add(new PlaylistWarp(ClientID));
                _code = listOfWarp[0].CreateWarp(DayOfWeek, ToAdmin);
                listOfWarp.Last().Version = DataVersionManager.Instance.GetDataVersionEx(ClientID);

                if (_code == -1)
                    throw new Exception("Video service error: Bad day of week.");
                if (_code == 1)
                    return null;
            }

            return listOfWarp;
        }

        #endregion
        #endregion
    }
}
